package cn.ant.service.custom;

import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cmd.AbstractDynamicInjectionCmd;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @Version 1.0
 * @Author:lss
 * @Date:2021/10/27
 * @Content:动态生成任务节点（在子流程中生成）
 */
@Slf4j
public class CustomSubProcessSerialUserTask extends AbstractDynamicInjectionCmd implements Command<Void> {
    //需要动态添加的新节点
    private DynamicUserTaskBuilder dynamicUserTaskBuilder;
    //新节点动态添加到的流程实例Id
    private String processInstanceId;
    //在流程中的哪一个节点后面添加新节点
    private FlowElement currentFlowElement;
    //新节点
    UserTask newUserTask=new UserTask();
    //子流程
    private SubProcess currentSubProcess;

    public CustomSubProcessSerialUserTask(String processInstanceId, SubProcess currentSubProcess, FlowElement currentFlowElement, DynamicUserTaskBuilder dynamicUserTaskBuilder) {
        this.processInstanceId = processInstanceId;
        this.currentFlowElement = currentFlowElement;
        this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
        this.currentSubProcess = currentSubProcess;
        //复制一个节点，除id或taskId等关键信息不一致，其他公共信息一致
        BeanUtils.copyProperties(this.currentFlowElement, newUserTask);
        /**将当前节点的数据复制到一个新对象 然后将id或taskId以及代理人，任务名字需要改*/
        //设置taskId
        if (this.dynamicUserTaskBuilder.getId() != null) {
            newUserTask.setId(this.dynamicUserTaskBuilder.getId());//自定义taskId
        } else {
            newUserTask.setId(this.dynamicUserTaskBuilder.nextTaskId(this.currentSubProcess.getFlowElementMap()));//整个流程的最后的一个taskId后面追加一个taskId
        }
        newUserTask.setAssignee(this.dynamicUserTaskBuilder.getAssignee());
        newUserTask.setName(this.dynamicUserTaskBuilder.getName());
    }

    @Override
    public Void execute(CommandContext commandContext) {
        createDerivedProcessDefinitionForProcessInstance(commandContext, processInstanceId);
        return null;
    }

    @Override
    protected void updateBpmnProcess(CommandContext commandContext, Process process, BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, DeploymentEntity deploymentEntity) {
        log.info("updateBpmnProcess.start");
        /**先处理子流程*/
        //将子流程的出入线记录
        List<SequenceFlow> subProcessOutSequenceFlows = new ArrayList<>();
        List<SequenceFlow> subProcessInSequenceFlows = new ArrayList<>();
        List<SequenceFlow> subOutgoingFlows = this.currentSubProcess.getOutgoingFlows();
        List<SequenceFlow> subIncomingFlows = this.currentSubProcess.getIncomingFlows();
        for (FlowElement flowElement : this.currentSubProcess.getFlowElements()) {
            log.info("this.currentSubProcess.getFlowElements ===》 {}",flowElement.getName());
        }
        subOutgoingFlows.stream().forEach(outgoingFlow -> {
            subProcessOutSequenceFlows.add(outgoingFlow);
//            process.removeFlowElement(outgoingFlow.getId());
        });
        subIncomingFlows.stream().forEach(incomingFlow -> {
            subProcessInSequenceFlows.add(incomingFlow);
//            process.removeFlowElement(incomingFlow.getId());
        });
        /**在子流程中添加新节点*/
        //获取当前子流程活动任务的出线
        UserTask currentUserTask = (UserTask) this.currentFlowElement;
        List<SequenceFlow> taskOutgoingFlows = currentUserTask.getOutgoingFlows();
        //将新建一条出线顺序流，出线源是当前活动节点的目标源，入线源是新节点的id
        for (int i = 0; i < taskOutgoingFlows.size(); i++) {
            SequenceFlow taskOutgoingFlow = taskOutgoingFlows.get(i);
            SequenceFlow newOutSequenceFlow = new SequenceFlow(this.newUserTask.getId(), taskOutgoingFlow.getTargetRef());
            newOutSequenceFlow.setId("seqId-"+UUID.randomUUID().toString());
            newOutSequenceFlow.setName("出线"+i);
            //将当前的顺序流从子流程中移除
            this.currentSubProcess.removeFlowElement(taskOutgoingFlow.getId());
            //将新的顺序流加到子流程中
            this.currentSubProcess.addFlowElement(newOutSequenceFlow);
        }
        //将新建一条入线顺序流，出线源是新节点的Id，入线源是当前活动节点id
        SequenceFlow newInSequenceFlow = new SequenceFlow(this.currentFlowElement.getId(), this.newUserTask.getId());
        //需要加上id，线条才能显示
        newInSequenceFlow.setId("seqId-"+UUID.randomUUID().toString());
        //将新构建的入线添加到子流程
        this.currentSubProcess.addFlowElement(newInSequenceFlow);
        //将新节点添加到子流程
        this.currentSubProcess.addFlowElement(this.newUserTask);
        //移除在主流程上的当前子流程，并将修改过的子流程添加到主流程
        process.removeFlowElement(this.currentSubProcess.getId());
        process.addFlowElement(this.currentSubProcess);
        /**自定义坐标：无*/
        new BpmnAutoLayout(bpmnModel).execute();
        log.info("updateBpmnProcess.end");
    }

    @Override
    protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity, ExecutionEntity executionEntity, List<ExecutionEntity> list) {

    }
}
